/*
 *    Copyright 2015 Kaopiz Software Co., Ltd.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.climber.android.commonres.widget.hkd;

import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.TextView;

import com.climber.android.commonres.R;

public class KProgressHUD {

    public enum Style {
        iLoading,Status
    }

    // To avoid redundant APIs, make the HUD as a wrapper class around a Dialog
    private ProgressDialog mProgressDialog;
    private float mDimAmount;
    private int mWindowColor;
    private int mCornerRadius; //px
    private int mLabelColor;
    private int mDetailColor;

    private Style mStyle;

    private int mMaxProgress;
    private boolean mIsAutoDismiss;
    private int mAuthDismissTime = 2000;

    private int mDelayShowTime;
    private Handler mUITimer;
    private boolean mFinished;

    //only called when style is Status
    private String mStatusTypeName;

    private KProgressHUD(Context context) {
        mProgressDialog = new ProgressDialog(context);
        mDimAmount = 0;
        //noinspection deprecation
        mWindowColor = context.getResources().getColor(R.color.mui_kprogresshud_default_color);
        mCornerRadius = dp2px(context, 4); //px
        mLabelColor = context.getResources().getColor(R.color.mui_kprogresshub_text_color);
        mDetailColor = context.getResources().getColor(R.color.mui_kprogresshub_text_color);
        mIsAutoDismiss = false;
        mDelayShowTime = 0;
        mFinished = false;
    }

    private int dp2px(Context context, float dpValue) {
        final float densityScale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * densityScale + 0.5f);
    }

    /**
     * Create a new HUD. Have the same effect as the constructor.
     * For convenient only.
     * @param context Activity context that the HUD bound to
     * @return An unique HUD instance
     */
    public static KProgressHUD create(Context context) {
        return new KProgressHUD(context);
    }

    /**
     * Specify the HUD style (not needed if you use a custom view)
     * @param style One of the KProgressHUD.Style values
     * @return Current HUD
     */
    public KProgressHUD setStyle(Context context, Style style) {
        mStyle = style;
        return this;
    }

    /**
     * Specify the dim area around the HUD, like in Dialog
     * @param dimAmount May take value from 0 to 1. Default to 0 (no dimming)
     * @return Current HUD
     */
    public KProgressHUD setDimAmount(float dimAmount) {
        if (dimAmount >= 0 && dimAmount <= 1) {
            mDimAmount = dimAmount;
        }
        return this;
    }

    /**
     * Set HUD size. If not the HUD view will use WRAP_CONTENT instead
     * @param width in px
     * @param height in px
     * @return Current HUD
     */
    public KProgressHUD setSize(int width, int height) {
        mProgressDialog.setSize(width, height);
        return this;
    }

    /**
     * Specify the HUD background color
     * @param color ARGB color
     * @return Current HUD
     */
    public KProgressHUD setBackgroundColor(int color) {
        mWindowColor = color;
        return this;
    }

    /**
     * Specify corner radius of the HUD (default is 10)
     * @param radius Corner radius in dp
     * @return Current HUD
     */
    public KProgressHUD setCornerRadius(int radius) {
        mCornerRadius = radius;
        return this;
    }

    public KProgressHUD setLabelColor(String colorStr){
        mLabelColor = Color.parseColor(colorStr);
        return this;
    }

    public KProgressHUD setDetailColor(String colorStr){
        mDetailColor = Color.parseColor(colorStr);
        return this;
    }

    /**
     * Optional label to be displayed.
     * @return Current HUD
     */
    public KProgressHUD setLabel(String label) {
        mProgressDialog.setLabel(label);
        return this;
    }

    /**
     * Optional label to be displayed
     * @return Current HUD
     */
    public KProgressHUD setLabel(String label, int color) {
        mProgressDialog.setLabel(label, color);
        return this;
    }

    /**
     * Optional detail description to be displayed on the HUD
     * @return Current HUD
     */
    public KProgressHUD setDetailsLabel(String detailsLabel) {
        mProgressDialog.setDetailsLabel(detailsLabel);
        return this;
    }

    /**
     * Optional detail description to be displayed
     * @return Current HUD
     */
    public KProgressHUD setDetailsLabel(String detailsLabel, int color) {
        mProgressDialog.setDetailsLabel(detailsLabel, color);
        return this;
    }

    /**
     * Max value for use in one of the determinate styles
     * @return Current HUD
     */
    public KProgressHUD setMaxProgress(int maxProgress) {
        mMaxProgress = maxProgress;
        return this;
    }

    /**
     * Set current progress. Only have effect when use with a determinate style, or a custom
     * view which implements Determinate interface.
     */
    public void setProgress(int progress) {
        mProgressDialog.setProgress(progress);
    }

    /**
     * Provide a custom view to be displayed.
     * @param view Must not be null
     * @return Current HUD
     */
    public KProgressHUD setCustomView(View view) {
        if (view != null) {
            mProgressDialog.setView(view);
        } else {
            throw new RuntimeException("Custom view must not be null!");
        }
        return this;
    }

    /**
     * Specify whether this HUD can be cancelled by using back button (default is false)
     *
     * Setting a cancelable to true with this method will set a null callback,
     * clearing any callback previously set with
     * {@link #setCancellable(DialogInterface.OnCancelListener)}
     *
     * @return Current HUD
     */
    public KProgressHUD setCancellable(boolean isCancellable) {
        mProgressDialog.setCancelable(isCancellable);
        mProgressDialog.setOnCancelListener(null);
        return this;
    }

    /**
     * Specify a callback to run when using the back button (default is null)
     *
     * @param listener The code that will run if the user presses the back
     * button. If you pass null, the dialog won't be cancellable, just like
     * if you had called {@link #setCancellable(boolean)} passing false.
     *
     * @return Current HUD
     */
    public KProgressHUD setCancellable(DialogInterface.OnCancelListener listener) {
        mProgressDialog.setCancelable(null != listener);
        mProgressDialog.setOnCancelListener(listener);
        return this;
    }

    public KProgressHUD setDismissListener(DialogInterface.OnDismissListener listener){
        if(listener != null){
            mProgressDialog.setOnDismissListener(listener);
        }
        return this;
    }

    /**
     * Specify whether this HUD closes itself if progress reaches max. Default is true.
     * @return Current HUD
     */
    public KProgressHUD setAutoDismiss(boolean isAutoDismiss) {
        mIsAutoDismiss = isAutoDismiss;
        return this;
    }

    public KProgressHUD setAutoDismissTime(int autoDismissTimes) {
        mAuthDismissTime = autoDismissTimes;
        return this;
    }

    /**
     * Grace period is the time (in milliseconds) that the invoked method may be run without
     * showing the HUD. If the task finishes before the grace time runs out, the HUD will
     * not be shown at all.
     * This may be used to prevent HUD display for very short tasks.
     * Defaults to 0 (no grace time).
     * @param delayShowTime Grace time in milliseconds
     * @return Current HUD
     */
    public KProgressHUD setDelayShowTime(int delayShowTime) {
        mDelayShowTime = delayShowTime;
        return this;
    }

    public KProgressHUD show() {
        if (!isShowing()) {
            mFinished = false;
            if (mDelayShowTime == 0) {
                mProgressDialog.show();
            } else {
                mUITimer = new Handler();
                mUITimer.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        if (mProgressDialog != null && !mFinished) {
                            mProgressDialog.show();
                        }
                    }
                }, mDelayShowTime);
            }
        }
        return this;
    }

    public boolean isShowing() {
        return mProgressDialog != null && mProgressDialog.isShowing();
    }

    public void dismiss() {
        mFinished = true;
        if (mProgressDialog != null && mProgressDialog.isShowing()) {
            mProgressDialog.dismiss();
        }
        if (mUITimer != null) {
            mUITimer.removeCallbacksAndMessages(null);
            mUITimer = null;
        }
    }

    private class ProgressDialog extends Dialog implements DialogInterface.OnShowListener{
        private View mView;
		private TextView mLabelText;
        private TextView mDetailsText;
        private String mLabel;
        private String mDetailsLabel;
        private FrameLayout mCustomViewContainer;
        private KBackgroundLayout mBackgroundLayout;
        private int mWidth, mHeight;

        ProgressDialog(Context context) {
            super(context);
        }

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            requestWindowFeature(Window.FEATURE_NO_TITLE);
            setContentView(R.layout.mui_kprogresshud_hud);

            Window window = getWindow();
            window.setBackgroundDrawable(new ColorDrawable(0));
            window.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
            WindowManager.LayoutParams layoutParams = window.getAttributes();
            layoutParams.dimAmount = mDimAmount;
            layoutParams.gravity = Gravity.CENTER;
            window.setAttributes(layoutParams);

            setCanceledOnTouchOutside(false);
            setOnShowListener(this);

            initViews();
        }

        private void initViews() {
            mBackgroundLayout = findViewById(R.id.hkd_background);
            mBackgroundLayout.setBackgroundColor(mWindowColor);
            mBackgroundLayout.setCornerRadius(mCornerRadius);
            if (mWidth != 0) {
                updateBackgroundSize();
            }

            mCustomViewContainer = findViewById(R.id.hkd_container);
            addViewToFrame(mView);

            mLabelText = findViewById(R.id.hkd_label);
            setLabel(mLabel, mLabelColor);
            mDetailsText = findViewById(R.id.hkd_details_label);
            setDetailsLabel(mDetailsLabel, mDetailColor);
        }

        private void addViewToFrame(View view) {
            if (view == null) return;

            if(mStyle == Style.iLoading){
                int wrapParam = dip2px(view.getContext(), 35);
                ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(wrapParam, wrapParam);
                mCustomViewContainer.addView(view, params);
            } else{
                int wrapParam = ViewGroup.LayoutParams.WRAP_CONTENT;
                ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(wrapParam, wrapParam);
                mCustomViewContainer.addView(view, params);
            }
        }

        private void updateBackgroundSize() {
            ViewGroup.LayoutParams params = mBackgroundLayout.getLayoutParams();
            params.width = mWidth;
            params.height = mHeight;
            mBackgroundLayout.setLayoutParams(params);
        }

        private void setProgress(int progress) {
            if (mIsAutoDismiss && progress >= mMaxProgress) {
                dismiss();
            }
        }

        private void setView(View view) {
            if (view != null) {
                mView = view;
                if (isShowing()) {
                    mCustomViewContainer.removeAllViews();
                    addViewToFrame(view);
                }
            }
        }

        private void setLabel(String label) {
            mLabel = label;
            if (mLabelText != null) {
                if (label != null) {
                    mLabelText.setText(label);
                    mLabelText.setVisibility(View.VISIBLE);
                } else {
                    mLabelText.setVisibility(View.GONE);
                }
            }
        }

        private void setDetailsLabel(String detailsLabel) {
            mDetailsLabel = detailsLabel;
            if (mDetailsText != null) {
                if (detailsLabel != null) {
                    mDetailsText.setText(detailsLabel);
                    mDetailsText.setVisibility(View.VISIBLE);
                } else {
                    mDetailsText.setVisibility(View.GONE);
                }
            }
        }

        private void setLabel(String label, int color) {
            mLabel = label;
            mLabelColor = color;
            if (mLabelText != null) {
                if (label != null) {
                    mLabelText.setText(label);
                    mLabelText.setTextColor(color);
                    mLabelText.setVisibility(View.VISIBLE);
                } else {
                    mLabelText.setVisibility(View.GONE);
                }
            }
        }

        private void setDetailsLabel(String detailsLabel, int color) {
            mDetailsLabel = detailsLabel;
            mDetailColor = color;
            if (mDetailsText != null) {
                if (detailsLabel != null) {
                    mDetailsText.setText(detailsLabel);
                    mDetailsText.setTextColor(color);
                    mDetailsText.setVisibility(View.VISIBLE);
                } else {
                    mDetailsText.setVisibility(View.GONE);
                }
            }
        }

        private void setSize(int width, int height) {
            mWidth = width;
            mHeight = height;
            if (mBackgroundLayout != null) {
                updateBackgroundSize();
            }
        }

        @Override
        public void onShow(DialogInterface dialog) {
            if(mIsAutoDismiss){
                mUITimer = new Handler();
                mUITimer.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        if (mProgressDialog != null && mProgressDialog.isShowing()) {
                            mProgressDialog.dismiss();
                        }
                    }
                }, mAuthDismissTime);
            }
        }

        private int dip2px(Context context, float dpValue) {
            final float scale = context.getResources().getDisplayMetrics().density;
            return (int) (dpValue * scale + 0.5f);
        }
    }
}
